Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'compare performance' view #3843

Merged
merged 47 commits into from
Jan 22, 2025
Merged

Conversation

asgerf
Copy link
Contributor

@asgerf asgerf commented Nov 27, 2024

Adds the 'Compare Performance' UI from the hackathon.

Activate via right-clicking on a query history item

Screenshot 2024-11-27 at 14 37 31

Shows overview of predicate evaluation costs

Screenshot 2024-11-27 at 14 38 56

Click a predicate to show its pipeline(s) and tuple counts per step

Screenshot 2024-11-27 at 14 37 11

Changes since the hackathon:

  • The integration with DCA has been left out for now. I'm hoping @esbena will follow up on this.
  • Added support for predicate-renaming, which was WIP and not demoable in time for the Hackathon demo.
  • Some UI performance improvements: using useMemo and moved some state into subcomponents where a state change cause as much re-rendering.
  • Some clean up of the commit history; mainly squashing simple bugfixes into an earlier commit.

Despite my attempts at cleaning the commit history, it might actually be easiest to review as one giant diff.

asgerf and others added 30 commits November 27, 2024 13:47
Adds a dropdown with (at present) two options: sorting by delta and
sorting by absolute delta.
This ensures we can use hooks after the check in the main component
A very hacky implementation that simply instantiates an empty
`PerformanceOverviewScanner` as the "from" column (i.e. with all values
empty). To see it in action, select a single query run in the query
history and pick "Compare Performance" from the context menu. Then
select the "Single run" option when prompted.
Only contains formatting changes
Predicate names can't be empty, but it can happen with the renaming feature added in the next commit.
@asgerf asgerf force-pushed the asgerf/compare-perf-view branch 2 times, most recently from 13e78a6 to ec223fa Compare November 27, 2024 13:00
@asgerf asgerf force-pushed the asgerf/compare-perf-view branch from ec223fa to aa528c6 Compare November 27, 2024 13:14
@asgerf asgerf marked this pull request as ready for review November 27, 2024 13:41
@asgerf asgerf requested a review from a team as a code owner November 27, 2024 13:41
Copy link
Contributor

@aeisenberg aeisenberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks ok to me in general. I haven't tried running this. It also seems isolated, so that if there is a problem, it is unlikely to affect other features.

There are a few questions and comments inside. Mostly, I'd like to either remove all TODOs and XXXs and replace them with a simple comment. If you think you will go back later to fix them, then please create an issue to track it.

extensions/ql-vscode/package.json Outdated Show resolved Hide resolved
};
}

protected onPanelDispose(): void {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to remove references to resultsView and labelProvider?

Suggested change
protected onPanelDispose(): void {}
protected onPanelDispose(): void {
this.resultsView = null;
this.labelProvider = null;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm...not sure what the lifecycle of the view is. Is there a single view instance created for the entire extension, or is it one view per window that's opened?

Copy link
Contributor Author

@asgerf asgerf Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The instance of this class persists across multiple open/close of the panel so I'd say we shouldn't dispose of these fields.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see how onPanelDispose is called in the super class. Your implementation here is fine.

extensions/ql-vscode/src/log-insights/log-scanner.ts Outdated Show resolved Hide resolved
*/
export interface PerformanceComparisonDataFromLog {
/** Names of predicates mentioned in the log */
names: string[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect the lengths of these arrays to be the same for all? If not, which ones will have different sizes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a more thorough description

/**
* List of indices into the `names` array for which we have seen a cache hit.
*
* TODO: only count cache hits prior to first evaluation?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below, if the TODO is tracked in an issue, can you add the issue? If it's not tracked, can you remove the TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove or resolve the TODOs 👍

For this one I went ahead and resolved it

singleItem: QueryHistoryInfo,
multiSelect: QueryHistoryInfo[] | undefined,
) {
// TODO: reduce duplication with 'handleCompareWith'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same...and below.

multiSelect: QueryHistoryInfo[] | undefined,
) {
// TODO: reduce duplication with 'handleCompareWith'
multiSelect ||= [singleItem];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a nice shortcut. I hadn't thought of that.

? allSelectedItems[1]
: allSelectedItems[0];
if (otherItem.databaseName !== dbName) {
throw new Error("Query databases must be the same.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: can you include the db names in this message?

Copy link
Contributor Author

@asgerf asgerf Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember why this condition is even here; it's possible we should just remove the restriction. I've asked @tausbn if he remembers why it's here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be fine with removing this. I have no recollection of why it would be necessary, and I don't think anything would blow up if you compare two different databases. At worst, you just get somewhat useless output.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this snippet of code was copy/pasted from findOtherQueryToCompare but isn't actually relevant for performance comparisons. I pushed a commit that removes the unnecessary check.

args.push(parseQName());
skipToken(",");
}
args.reverse();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the reverse?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment to clarify

Note that the tokens stream is parsed in reverse order. This is simpler, but may look confusing initially.

Comment on lines +139 to +142
if (prefix != null) {
result.push(prefix.abbreviate());
result.push("::");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite complex to me. It is combining prefix from the closure with result, a local variable. This function is complex enough that maybe VisitResult should be a class and prefix is passed in as a private field. Then this function can become a member of VisitResult.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is a matter of taste. Personally I find captured variables to be simpler to follow than fields as you can just jump to it to see what it is. This actually started out as a class, which I converted to a closure to simplify it. Do you feel strongly about doing this rewrite?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine by me. I can understand your perspective even if it is not how I would have written it. And it doesn't seem incorrect to me.

@asgerf
Copy link
Contributor Author

asgerf commented Jan 17, 2025

Thanks for the review @aeisenberg! I've responded to all comments

Copy link
Contributor

@aeisenberg aeisenberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for addressing my comments.

After you merge, you can do a release. If you don't feel comfortable doing a release, then send a message to the internal slack channel and we can help you.

};
}

protected onPanelDispose(): void {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see how onPanelDispose is called in the super class. Your implementation here is fine.

Comment on lines +139 to +142
if (prefix != null) {
result.push(prefix.abbreviate());
result.push("::");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine by me. I can understand your perspective even if it is not how I would have written it. And it doesn't seem incorrect to me.

@asgerf asgerf merged commit ffed4b6 into github:main Jan 22, 2025
16 checks passed
@asgerf
Copy link
Contributor Author

asgerf commented Jan 22, 2025

Thanks for the review! I've merged for now, and will see if I can do a release.

@robertbrignull robertbrignull mentioned this pull request Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants